package com.zmn.mcc.business.impl.organize;

import com.alibaba.fastjson.JSONObject;
import com.zmn.base.plat.engine.common.constant.PlatEngineConsts;
import com.zmn.common.constant.GlobalConsts;
import com.zmn.common.dto2.ResponseDTO;
import com.zmn.common.utils.number.NumberUtil;
import com.zmn.common.utils.string.StringUtil;
import com.zmn.manager.common.database.annotation.ReadOnlyConnection;
import com.zmn.mcc.business.interfaces.organize.OrganizeBService;
import com.zmn.mcc.common.constant.MenuConsts;
import com.zmn.mcc.common.dto.organize.OrganizeDRO;
import com.zmn.mcc.cache.OrganizeCache;
import com.zmn.mcc.model.entity.menu.McMenu;
import com.zmn.mcc.model.entity.organize.McOrganize;
import com.zmn.mcc.model.entity.organize.McOrganizeQuery;
import com.zmn.mcc.services.interfaces.organize.OrganizeService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cglib.beans.BeanCopier;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author heguanghua
 * @since 2020/04/14 22:15
 */
@Service
public class OrganizeBServiceImpl implements OrganizeBService {
    protected Logger logger = LoggerFactory.getLogger(OrganizeBServiceImpl.class);

    private final BeanCopier copier = BeanCopier.create(McOrganize.class, OrganizeDRO.class, false);

    @Resource
    private OrganizeService organizeService;
    @Resource
    private OrganizeCache organizeCache;

    @Override
    public OrganizeDRO getByKey(Integer orgId) {
        McOrganize organize = organizeService.findByKey(orgId);
        OrganizeDRO dro = new OrganizeDRO();
        if (!Objects.isNull(organize)) {
            copier.copy(organize, dro, null);
        }
        return dro;
    }

    @Override
    public List<McOrganize> listOrganize(McOrganizeQuery query) {

        List<McOrganize> items = organizeService.listByQuery(query);
        Integer level = query.getLevel();
        int l = level == null ? 100 : level;
        return items.stream().filter(item -> {
            if (item.getLevel() == null) {
                return true;
            }
            return item.getLevel().shortValue() <= l;
        }).collect(Collectors.toList());
    }

    @Override
    @ReadOnlyConnection
    public List<McOrganize> listByPlatAndLevel(Integer plat, Integer level, Integer status) {
        McOrganizeQuery query = buildQuery(Objects.isNull(plat) ? null : Collections.singletonList(plat), level, status);
        List<McOrganize> items = organizeService.listByQuery(query);
        connectingPlatName(items, plat);
        return items;
    }

    @Override
    public List<McOrganize> listByPlatsAndLevelAndParentIds(List<Integer> plats, Integer level, Integer status,
                                                            List<Integer> parentIdList) {

        McOrganizeQuery query = buildQuery(plats, level, status, parentIdList);
        List<McOrganize> items = organizeService.listByQuery(query);
        connectingPlatName(items, PlatEngineConsts.TOP_ID);
        return items;
    }

    // region 新增/修改组织架构

    @Override
    public ResponseDTO addOrganize(McOrganize organize) {

        try {

            // 校验
            ResponseDTO checkResult = this.checkOrganize(organize);
            if (!checkResult.isSuccess()) {
                return checkResult;
            }

            // 初始化
            this.initOrganize(organize);

            // 组织架构信息
            organizeService.insert(organize);

            // 更新缓存
            organizeCache.setOrganize(organize.getOrgId());

            return ResponseDTO.success(organize.getOrgId(), "新增组织架构成功");

        } catch (Exception ex) {
            logger.error(String.format("[ZMN]新增组织架构失败,organize:[%s],ex:[%s]", JSONObject.toJSONString(organize), ex.getMessage()));
            return ResponseDTO.fail("新增组织架构失败");
        }
    }

    @Override
    public ResponseDTO modifyOrganize(McOrganize organize) {

        try {

            // 校验
            ResponseDTO checkResult = this.checkOrganize(organize);
            if (!checkResult.isSuccess()) {
                return checkResult;
            }

            // 初始化
            this.initOrganize(organize);

            // 组织架构信息
            organizeService.updateByKey(organize);

            // 更新缓存
            organizeCache.setOrganize(organize.getOrgId());

            return ResponseDTO.success(organize.getOrgId(), "修改组织架构成功");

        } catch (Exception ex) {
            logger.error(String.format("[ZMN]修改组织架构失败,organize:[%s],ex:[%s]", JSONObject.toJSONString(organize), ex.getMessage()));
            return ResponseDTO.fail("修改组织架构失败");
        }
    }


    /**
     * 校验组织信息
     *
     * @param organize
     * @return
     */
    private ResponseDTO checkOrganize(McOrganize organize) {

        if (StringUtil.isBlank(organize.getOrgName())) {
            return ResponseDTO.fail("组织名称不能为空");
        }

        // 如新增1级组织，则需校验plat标识
        if (NumberUtil.isNullOrZero(organize.getOrgId())
                && (NumberUtil.isNullOrZero(organize.getParentId()) || organize.getParentId() <= GlobalConsts.TOP_ID)) {
            if (NumberUtil.isNullOrZero(organize.getPlat())) {
                return ResponseDTO.fail("未指定组织所属平台");
            }
        }

        return ResponseDTO.success(null, "OK");
    }

    /**
     * 初始化组织
     *
     * @param organize
     */
    private void initOrganize(McOrganize organize) {

        // 组织层级
        Integer level = 0;
        if (NumberUtil.isNotNullOrZero(organize.getParentId()) && organize.getParentId() > GlobalConsts.TOP_ID) {
            McOrganize parent = organizeService.findByKey(organize.getParentId());
            organize.setPlat(parent.getPlat());
            level = Optional.ofNullable(parent.getLevel()).orElse(GlobalConsts.TOP_ID);
            level += 1;
        } else {
            level = GlobalConsts.TOP_ID;
        }
        organize.setLevel(level);
    }
    // endregion

    /**
     * 组合平台名称
     */
    private void connectingPlatName(List<McOrganize> items, Integer plat) {
        if (NumberUtil.isNullOrZero(plat)) {
            Map<Integer, String> map = organizeCache.getPlatMap();
            for (McOrganize item : items) {
                if (item.getLevel().equals(1)) {
                    continue;
                }
                item.setOrgName(String.format("[%s]%s", map.get(item.getPlat()), item.getOrgName()));
            }
        }
    }

    private McOrganizeQuery buildQuery(List<Integer> plats, Integer level, Integer status) {
        McOrganizeQuery query = new McOrganizeQuery();
        query.setPlats(plats);
        query.setLevel(level);
        query.setStatus(status);
        return query;
    }

    private McOrganizeQuery buildQuery(List<Integer> plats, Integer level, Integer status, List<Integer> parentIdList) {
        McOrganizeQuery query = buildQuery(plats, level, status);
        query.setParentIdList(parentIdList);
        return query;
    }
}
